# -*- coding: utf-8 -*-
# @Date：2024/7/21 15:26:03
# @Author：CJiaの青姝
# @FileName：menu
# @Editor：PyCharm2024
# @Remark：
from typing import List, Any
from typing_extensions import Self

from auths.models import Users, UsersRole
from system.models import Menu, MenuButton, RoleMenu
from ninja import Router, Field, Query, ModelSchema
from ninja import Router

from utils.cj_ninja import CjFilters
from utils.list_to_tree import list_to_route, list_to_tree
from utils.serializes import model_dict_list
from utils.cj_crud import create, delete, batch_delete, update, condition, single
from utils.cj_response import SuccessResponse, ErrorResponse

router = Router()


class Filters(CjFilters):
    title: str = Field(None, description="菜单名称", alias='title')

    class Config:
        title = "菜单类型查询参数"


class MenuSchemaIn(ModelSchema):
    parent_id: int = Field(None, description="父级菜单id", alias="parent_id")

    def validate(cls, value: Any) -> Self:
        if value.title == '' or value.title is None:
            return "菜单名称不能为空", 400
        elif value.type == '' or value.type is None:
            return "菜单类型不能为空", 400
        # 返回请求数据
        return value, 200

    def model_validate(
            cls,
            obj: Any,
            *,
            strict: bool | None = None,
            from_attributes: bool | None = None,
            context: Any | None = None,
    ) -> Self:
        if obj.title == '' or obj.title is None:
            return "菜单名称不能为空", 400
        elif obj.type == '' or obj.type is None:
            return "菜单类型不能为空", 400
        # 判断重复
        if Menu.objects.filter(title=obj.title).exists():
            return "菜单名称不支持重复", 400
        # 判断菜单类型
        if obj.parent_id:
            parent_menu = Menu.objects.get(id=obj.parent_id)
            if parent_menu.type:
                # 如果上级菜单不是目录，则将菜单类型改为目录
                parent_menu.type = 0
                parent_menu.save()
        # 返回请求数据
        return obj, 200

    class Config:
        title = '创建菜单参数'
        model = Menu
        model_exclude = ['id', 'creator', 'modifier', 'create_time', 'update_time', 'parent']


class MenuButtonSchemaIn(ModelSchema):
    menu_id: int = Field(None, description="所属菜单id", alias="menu_id")

    def model_validate(
            cls,
            obj: Any,
            *,
            strict: bool | None = None,
            from_attributes: bool | None = None,
            context: Any | None = None,
    ) -> Self:
        if obj.title == '' or obj.title is None:
            return "按钮名称不能为空", 400
        elif obj.code == '' or obj.code is None:
            return "权限标识不能为空", 400
        elif obj.api == '' or obj.api is None:
            return "请求地址不能为空", 400
        elif obj.method == '' or obj.method is None:
            return "请求方法不能为空", 400
        elif obj.menu_id == '' or obj.menu_id is None:
            return "所属菜单不能为空", 400
        # 判断菜单类型
        if Menu.objects.filter(parent_id=obj.menu_id).exists():
            if not Menu.objects.get(id=obj.menu_id).type:
                return "目录下不支持按钮", 400
        # 返回请求数据
        return obj, 200

    class Config:
        title = '创建菜单权限按钮参数'
        model = MenuButton
        model_exclude = ['id', 'creator', 'modifier', 'create_time', 'update_time', 'name', 'menu']


class MenuSchemaOut(ModelSchema):
    key: int = Field(None, description="唯一标识符", alias='key')

    class Config:
        title = '菜单对象实例'
        model = Menu
        model_fields = "__all__"


class MenuButtonSchemaOut(ModelSchema):
    key: int = Field(None, description="唯一标识符", alias='key')

    class Config:
        title = '菜单按钮对象实例'
        model = MenuButton
        model_fields = "__all__"


class SchemaOut(ModelSchema):
    items: List[MenuButtonSchemaOut]

    class Config:
        title = '菜单权限对象实例'
        model = Menu
        model_fields = "__all__"


@router.post("/menu", summary="创建菜单")
def create_menu(request, data: MenuSchemaIn):
    """ 创建菜单并自动生成对应菜单按钮权限 """
    message, code = data.model_validate(data)
    if code == 400:
        return ErrorResponse(msg=message)
    # 调用新增方法
    result = create(request, Menu, message)
    # 自动生成对应菜单按钮权限
    if result['type']:
        # 模块
        module = Menu.objects.get(id=result['parent']).name
        # 循环生成
        button_list = [
            {"title": "新增", "code": f"{module}:{result['name']}:create", "api": f"/api/v1/{module}/{result['name']}",
             "method": 2, "menu_id": result['id']},
            {"title": "删除", "code": f"{module}:{result['name']}:delete",
             "api": f"/api/v1/{module}/{result['name']}/" + '{' + result['name'] + '_id}',
             "method": 4, "menu_id": result['id']},
            {"title": "修改", "code": f"{module}:{result['name']}:update",
             "api": f"/api/v1/{module}/{result['name']}/" + '{' + result['name'] + '_id}',
             "method": 3, "menu_id": result['id']},
            {"title": "查询", "code": f"{module}:{result['name']}:views", "api": f"/api/v1/{module}/{result['name']}",
             "method": 1, "menu_id": result['id']},
        ]
        for data in button_list:
            # 循环生成
            create(request, MenuButton, data)
    # 返回结果
    return SuccessResponse(data=result, msg="新增成功")


@router.post("/menuButton", summary="创建菜单权限按钮")
def create_menu_button(request, data: MenuButtonSchemaIn):
    """ 创建菜单权限按钮 """
    message, code = data.model_validate(data)
    if code == 400:
        return ErrorResponse(msg=message)
    # 调用新增方法
    result = create(request, MenuButton, message)
    # 返回结果
    return SuccessResponse(data=result, msg="新增成功")


@router.delete("/menu/{menu_id}", response=MenuSchemaIn, summary="删除菜单")
def delete_menu(request, menu_id: int):
    """ 删除按钮或删除菜单并自动删除所属的菜单按钮 """
    # 调用删除方法
    result, code = delete(Menu, menu_id)
    if code != 200:
        return ErrorResponse(code=code, msg=result)
    # 删除所属的菜单按钮
    menu_button_ids = MenuButton.objects.filter(menu_id=menu_id).values('id')
    batch_delete(request, MenuButton, menu_button_ids)
    # 返回结果
    return SuccessResponse(data=result, msg="删除成功")


@router.delete("/menuButton/{menu_button_id}", response=MenuSchemaIn, summary="删除菜单权限按钮")
def delete_menu(request, menu_button_id: int):
    """ 删除菜单权限按钮 """
    # 调用删除方法
    result, code = delete(Menu, menu_button_id)
    if code != 200:
        return ErrorResponse(code=code, msg=result)
    # 返回结果
    return SuccessResponse(data=result, msg="删除成功")


@router.put("/menuButton/{menu_button_id}", response=SchemaOut, summary="更新菜单权限按钮")
def update_menu_button(request, menu_button_id: int, data: MenuSchemaIn):
    message, code = data.validate(data)
    if code == 400:
        return ErrorResponse(msg=message)
    # 判断重复
    if Menu.objects.filter(title=message.title).exists():
        if Menu.objects.get(title=message.title).id != menu_button_id:
            return ErrorResponse(msg="菜单名称已存在，请重新输入")
    # 调用修改方法
    result = update(request, Menu, message, menu_button_id)
    # 返回结果
    return SuccessResponse(data=result, msg="更新成功")


@router.get("/menu/route/list", response=List[MenuSchemaOut], summary="获取菜单树列表")
def list_menu_tree(request, filters: Filters = Query(...)):
    """ 获取菜单树列表 """
    # 获取菜单列表
    result = condition(request, Menu, filters)
    # 将查询集转换成树形结构
    menu_tree = list_to_tree(result)
    # 返回结果
    return SuccessResponse(data=menu_tree, msg="获取成功")


@router.get("/menu/route/tree", summary="获取用户菜单树")
def menu_route_tree(request):
    """ 用于前端获取当前用户的权限菜单 """
    user_obj = Users.objects.get(id=request.user_id)
    role_ids = UsersRole.objects.filter(user_id=user_obj.id).values_list('role_id', flat=True)
    menu_ids = RoleMenu.objects.filter(role_id__in=role_ids).values_list('menu_id', flat=True)
    queryset = Menu.objects.filter(id__in=menu_ids, status=1).values()
    menu_tree = list_to_route(list(queryset))
    result = model_dict_list(menu_tree)
    return SuccessResponse(data=result, msg="获取成功")


@router.get("/menu/button/tree", summary="获取菜单权限树列表")
def list_menu_button_tree(request, filters: Filters = Query(...)):
    """ 获取菜单权限树列表 """
    # 获取菜单列表
    menu_list = condition(request, Menu, filters)
    # 将查询集转换成树形结构
    menu_tree = list_to_tree(menu_list)
    # 将树形结构转换成权限树形结构
    for item in menu_tree:
        if 'children' in item and item['children'] is not None:
            if len(item['children']) != 0:
                for child in item['children']:
                    child['children'] = model_dict_list(list(MenuButton.objects.filter(menu_id=child['id']).values()))
            else:
                pass
    # 返回结果
    return SuccessResponse(data=menu_tree, msg="获取成功")


@router.get("/menu/{menu_id}", response=SchemaOut, summary="获取菜单权限对象")
def get_custom(request, menu_id: int):
    """ 获取菜单权限对象 """
    # 调用根据id获取指定对象方法
    result = single(request, Menu, id=menu_id)
    # 获取菜单按钮
    result['items'] = list(MenuButton.objects.filter(menu_id=menu_id).values())
    # 返回结果
    return SuccessResponse(data=result)
